import { Graph, Markup, Node } from '@antv/x6';
import { v4 as guid } from "uuid";
import { CellType } from '../enums';
import { FieldUpdatedEvent, MonitorBoardConfig } from '../models';
import { cornerRadio } from './cornerRadio';
import { Constance } from './nodes-util';
import { Logger } from 'src/service/logger';

export class MonitorBoardNode extends Node {
  static ShapeName = "monitor-board";

  static register() {
    Graph.registerNode(MonitorBoardNode.ShapeName, MonitorBoardNode, true);
  }

  static unregister() {
    Graph.unregisterNode(MonitorBoardNode.ShapeName);
  }

  static getMeta(cfg?: MonitorBoardConfig): Node.Metadata {
    const { monitorBoard: _size } = Constance.sizes;
    const size = { width: cfg?.Width ?? _size.width, height: cfg?.Height ?? _size.height };
    const position = { x: cfg?.X ?? 0, y: cfg?.Y ?? 0 };

    const config: MonitorBoardConfig = {
      Id: cfg?.Id ?? guid(),
      Name: cfg?.Name ?? "监控板",
      Width: size.width,
      Height: size.height,
      X: position.x,
      Y: position.y,
      Plc: cfg?.Plc ?? {
        Ip: "",
        Port: 102,
        Interval: 1000,
      },
      Fields: cfg?.Fields ?? [],
      Type: CellType.MonitorBoard,
    };

    const meta = {
      shape: MonitorBoardNode.ShapeName,
      size: size,
      position: position,
      id: cfg?.Id,
      attrs: {
        plc: {
          text: `PLC[${config.Plc.Ip}:${config.Plc.Port}]`,
        },
        title: {
          text: config.Name,
        }
      },
      data: {
        cfg: config
      },
      zIndex: 2,
    };
    return meta;
  }


  update(cfg: MonitorBoardConfig) {
    this.attr('title/text', cfg.Name);
    this.attr("plc/text", `PLC[${cfg.Plc.Ip ?? 'ip'}:${cfg.Plc.Port ?? 'port'}]`);

    this.data.cfg = cfg;

    const markup: Markup = this.getMarkup();

    const fieldAttrs: { [key: string]: any; } = {};

    const fieldMarkup: Markup.JSONMarkup = {
      tagName: "g",
      children: []
    };
    if (Markup.isJSONMarkup(markup)) {
      let yOffset = 0;
      const yGap = 10;
      cfg.Fields.filter(f => f.Visible == true).forEach((f, i) => {
        const fontSize = f.FontSize ?? 12;
        yOffset += yGap + fontSize;
        const attrName = `Field${f.Name}`;
        const item: Markup.JSONMarkup = {
          tagName: 'text',
          selector: attrName,
          attrs: {
            textAnchor: 'start',
            textVerticalAnchor: 'top',
            x: 20,
            y: yOffset,
            fontSize,
            class: 'text-shadow-1',
          }
        };

        fieldMarkup.children?.push(item);

        fieldAttrs[attrName] = {
          fill: '#fff',
          text: `${f.Description ?? f.Name}|`
        };
      });

      const newMarkup: Markup = [
        {
          tagName: 'rect',
          selector: 'body',
        },
        {
          tagName: "text",
          selector: "plc",
        },
        {
          tagName: 'text',
          selector: 'title',
        },
        fieldMarkup,
      ];
      this.setMarkup(newMarkup);

      for (const attrName in fieldAttrs) {
        if (Object.prototype.hasOwnProperty.call(fieldAttrs, attrName)) {
          const val = fieldAttrs[attrName];
          this.attr(attrName, val);
        }
      }
    }
  }

  fieldValueUpdated(e: FieldUpdatedEvent) {
    const { cfg }: { cfg: MonitorBoardConfig; } = this.data;
    this.data.Values = e.Values;


    cfg.Fields.forEach((f, i) => {
      if (Object.prototype.hasOwnProperty.call(e.Values, f.Name!)) {
        const value = e.Values[f.Name];
        const map = f.Maps.find(a => a.Key == value);
        if (map) {
          const { Color, Description } = map;

          this.attr(`Field${f.Name}`, {
            fill: Color,
            Text: `${f.Description ?? f.Name} | (${value}) ${Description}`,
          });
        } else {
          this.attr(`Field${f.Name}`, {
            fill: "rgba(255,255,255,0.6)",
            Text: `${f.Description ?? f.Name} | (${value})`,
          });
        }
      }
    });
  }

  getConfig(): MonitorBoardConfig {
    const { x, y } = this.position();
    const { width, height } = this.size();
    const cfg: MonitorBoardConfig = {
      ...this.data.cfg,
      X: x,
      Y: y,
      Width: width,
      Height: height,
      Type: CellType.MonitorBoard,
    };

    return cfg;
  }
  logger?: Logger;
  setLogger(logger: Logger) {
    this.logger = logger;
  }
  bindPositionAndSizeChange() {
    this.on("change:position", ({ current }) => {
      const cfg = {
        ...this.data.cfg,
        X: current?.x,
        Y: current?.y
      };
      this.data.cfg = cfg;
    });
    this.on("change:size", ({ current }) => {
      const cfg = {
        ...this.data.cfg,
        Width: current?.width,
        Height: current?.height
      };
      this.data.cfg = cfg;
    });
  }
}

MonitorBoardNode.config({
  markup: [
    {
      tagName: 'rect',
      selector: 'body',
    },
    {
      tagName: "text",
      selector: "plc",
    },
    {
      tagName: 'text',
      selector: 'title',
    },
  ],
  attrs: {
    body: {
      refWidth: 1,
      refHeight: 1,
      strokeDasharray: '1 5',
      strokeDashoffset: 2.5,
      stroke: '#8f8f8f',
      strokeWidth: 0.5,
      fill: '#cccccc11',
      ...cornerRadio
    },
    plc: {
      text: 'PLC',
      class: 'text-shadow-1',
      refX: '0%',
      refY: '100%',
      x: 10,
      y: -10,
      fill: 'rgba(255,255,255,0.25)',
      fontSize: 16,
      textAnchor: 'start',
      textVerticalAnchor: 'bottom',
    },
    title: {
      text: '监控板',
      class: 'text-shadow-1',
      refX: '100%',
      refY: '100%',
      x: -10,
      y: -10,
      fill: 'rgba(255,255,255,0.25)',
      fontSize: 20,
      textAnchor: 'end',
      textVerticalAnchor: 'bottom',
    },
  }
});